perm filename NTKBAS.MF[MF,ALS] blob sn#760284 filedate 1984-07-05 generic text, type C, neo UTF8
COMMENT āŠ—   VALID 00015 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	% dimensional variables
C00005 00003	% global dimensional variables for characters
C00008 00004	% assignments to global dimensions
C00011 00005	% procedure for drawing character boxes
C00013 00006	% basic procedures for drawing straight strokes
C00016 00007	% procedure for making serifs
C00017 00008	% basic procedures for drawing curved strokes
C00019 00009	% general procedure for making arches
C00021 00010	% procedure for making arches in h,n,m
C00023 00011	% general procedures for drawing bowls
C00026 00012	def cup(suffix z)=
C00029 00013	% procedure for drawing terminals in a,c,s
C00032 00014	% procedure for drawing bowls in b,d,p,q
C00035 00015	% open a display window
C00036 ENDMK
CāŠ—;
% dimensional variables

numeric div,dmm;
div=if mode=proof then 4
    elseif mode=sun then 5
    elseif mode=smoke then 10
    fi;
dmm=(384/25.4)/div;	% nominal number of Dover pixels in 1 mm

numeric hmm,vmm,	% horizontal and vertical dimensional millimetres
    hsmm,vsmm;		%			  stroke-weight

hmm=dmm*expansion;
vmm=dmm;
hsmm=dmm*boldness;
vsmm=vmm;		% for the moment

% vertical proportions: originally 36ths of the body size

numeric ascender_height,cap_height,x_height,baseline,descender_length;

    ascender_height=29;
    cap_height=28;
    x_height=20;
    baseline=0;
    descender_length=-9;

% parameters for drawing

numeric cap_height,vdiv;	% size and vertical increment for proofmode drawings
    cap_height=round(100 vmm);
    vdiv=cap_height/28;

numeric ascender_line,cap_line,x_line,descender_line;	% vertical references for grid

    ascender_line=round(ascender_height*vdiv);
    cap_line=cap_height;
    x_line=round(x_height*vdiv);
    descender_line=round(descender_length*vdiv);
% global dimensional variables for characters

% basic horizontal dimensions

  numeric sidebearing_straight,		% sidebearing for straight strokes
	sidebearing_curved,		%		  curved
	sidebearing_r,			%		  f,j,r

	arch_stroke_separation,
	bowl_stroke_separation_a,	% in bowl of a
	bowl_stroke_separation_b,	%	     b,p
	bowl_stroke_separation_d,	%	     d,g,q
	round_stroke_separation,	%    round characters

	upper_setback_width,		% setback width for notches in m,n etc
	lower_setback_width,		%			       a,u


% basic vertical dimensions

	upper_setback_height,
	upper_arch_spring_height,

	lower_arch_spring_height_a,	% for a,b,p,q
	lower_arch_spring_height_d,	%     b
	lower_arch_spring_height_u,	%     u

	a_bar_height,
	e_bar_height,

	overshoot,		% vertical overshoot in arches and round characters


% weight-related dimensions

	stroke_weight,			% normal weight of straight upright strokes
	ascender_weight,
	bowl_stroke_weight,		%	  	   upright strokes in bowls

	horizontal_stroke_weight,	%	  	   straight horizontals
	t_bar_weight,			%		   crossbars in f and t

	horizontal_curve_weight,	% in horizontals of round characters
	vertical_curve_weight,		%    verticals

	horizontal_arch_weight,

	upper_arch_spring_weight,
	lower_arch_spring_weight,


% dimensions of serifs

	serif_weight,

	lower_external_serif_length,
	lower_internal_serif_length,
	upper_external_serif_length,


% useful variables for drawing

	lhsb,
	rhsb,
	weight,
	width,
	slant,
	slant_correction;

pair top,bottom,shift;
% assignments to global dimensions

slant=0.25;

% vertical dimensions

overshoot=round(2 vmm);

upper_setback_height=round(0.90[baseline,x_line]);
upper_arch_spring_height=0.89[baseline,x_line];

lower_arch_spring_height_a=0.88[x_line,baseline];
lower_arch_spring_height_b=0.90[x_line,baseline];
lower_arch_spring_height_u=0.86[x_line,baseline];

a_bar_height=round(0.62[baseline,x_line]);
e_bar_height=round(0.59[baseline,x_line]);


% horizontal dimensions

slant_correction=if not (slant_switch) then zero
		 else: slant*(x_line-baseline)/2
		 fi;

sidebearing_straight=round(14 hmm-slant_correction);
sidebearing_curved=round(6.5 hmm-slant_correction);
sidebearing_r=round(3.5 hmm-slant_correction);

arch_stroke_separation=round(42 hmm);
bowl_stroke_separation_a=round(43 hmm);
bowl_stroke_separation_b=round(46 hmm);
bowl_stroke_separation_d=round(46 hmm);
round_stroke_separation=round(52 hmm);

upper_setback_width=round(2.5 hmm);
lower_setback_width=round(1.25 hmm);

lower_external_serif_length=round(8.5 hmm);
lower_internal_serif_length=lower_external_serif_length-round(1.5 hmm);
upper_external_serif_length=lower_external_serif_length+round(1.5 hmm);


% weights

stroke_weight=round(13 hsmm);
ascender_weight=round(0.95*stroke_weight);
bowl_stroke_weight=ascender_weight;

vertical_curve_weight=round(1.05*stroke_weight);

horizontal_curve_weight=round(6.75 vsmm);
horizontal_arch_weight=round(8.75 vsmm);

horizontal_stroke_weight=round(6.5 vsmm);
t_bar_weight=horizontal_curve_weight-overshoot;

serif_weight=round(4.5 vsmm);

upper_arch_spring_weight=5.5 vsmm;
lower_arch_spring_weight=upper_arch_spring_weight;
% procedure for drawing character boxes

def widthbox(expr w)=

  begingroup save c;pair c[];

    def box(suffix s)(text t)=

      for i:=t do line(s[i]);endfor

    enddef;

    def mark(suffix s)(text t)=

    % draws crosses at s[i]

      begingroup save a,d,p;numeric a;pair d,p;

	a=2 dmm;	% arm length of cross

	for i:=t do

	  p:=s[i];d:=(a,0);line(p shifted -d..p shifted d);
	  d:=(0,a);line(p shifted -d..p shifted d);

	endfor

      endgroup

    enddef;

    c1=(0,descender_line);
    c2=(w,descender_line);
    c3=(w,ascender_line);
    c4=(0,ascender_line);			% outside corners

    c5=(0,0);
    c6=(w,0);					% baseline

    c7=(0,x_line);
    c8=(w,x_line);

    c9=(0,cap_line);
    c10=(w,cap_line);

    if grid then

      begingroup save p;path p[];

	p1=c1..c2 & c2..c3 & c3..c4 & c4..c1 & cycle;

	p2=c5..c6;

	p3=c7..c8;

	p4=c9..c10;

	box(p)(1,2,3,4)

      endgroup

    elseif mode=smoke then mark(c)(1,2,3,4,5,6,7,8,9,10)

    fi;

    if ddisplay then showit fi

  endgroup

enddef;
% basic procedures for drawing straight strokes

% all these procedures deliver paths for use with the `draw' command

def vstroke(expr top,bottom,weight,taper,location)=

% draws straight-sided strokes from pair(top) to pair(bottom), to left or right,
% with thickness numeric(weight) at top, tapering by numeric(taper) at bottom

  begingroup save p;pair p[];

    p1=top;p2=bottom;
    p3=p1 shifted (weight,0);p4=p2 shifted (weight-taper,0);

    (p1..p2 & p2..p4 & p4..p3 & p3..p1 & cycle)

    if location=left then reflected (p1,p2) fi

    if slant_switch then slanted slant fi

  endgroup

enddef;


def vertical(expr t,b,w,loc)=

% simple application of vstroke
% draws vertically from pair(t) to numeric(b), with zero taper

  begingroup save p;pair p;

    xpart p=xpart t;
    ypart p=b;

    vstroke(t,p,w,zero,loc)

  endgroup

enddef;


def hstroke(expr start,finish,weight,taper,location)=

% draws straight-sided strokes from pair(start) to pair(finish), with thickness
% numeric(weight) at start, tapering by numeric(taper) at finish

  begingroup save p;pair p[];

    p1=start;p2=finish;
    p11=offset(p1,p2,weight,right);
    p12=offset(p2,p1,(weight-taper),left);

    (p1..p2 & p2..p12 & p12..p11 & p11..p1 & cycle)

    if ((location=above) or (location=left)) then reflected(p1,p2) fi

    if slant_switch then slanted slant fi

  endgroup

enddef;



% procedure for making serifs

% makes slab serifs of weight serif_weight

def serif(expr length,direction,position)=

  begingroup save l,w;numeric l,w;

    l=ypart position;w=l-serif_weight;

    if (l=baseline) or (l=descender_line) then w:=l+serif_weight
    fi;

    vertical(position,w,length,direction)

  endgroup

enddef;
% basic procedures for drawing curved strokes

% these procedures draw through points in z[], which are numbered according
% to a standard convention

% z1 is the start point (on the outside of the curve)
% z2	first horizontal (or vertical) tangent
% z3	      45-degree tangent point
% z4	vertical (or horizontal) tangent
% z5	second 45-degree tangent point
% z6	       horizontal (or vetrical) tangent
% z7	outside finish point
% z8	outer start slope point
% z9	      finish

% points z11 - z19 are the corresponding points on the inside of the curve

% curves can go right (like the bowl of small p) with z1 on the left
%		left			      d			right
%		up (like the top of small e)
%		down	     bottom

% the latter two kinds always have point z1 on the left

% procedures like `arch' that don't use all the points skip those that
% aren't appropriate

% general procedure for making arches

def arch(suffix z)(expr start_weight)=

  begingroup save a,b,d,p;numeric a,b;pair d[];path p[];

    % test for directions in arch

    a=if x4>x1 then 1
      else: -1
      fi;
    b=if y2>y7 then -1
      else: 1
      fi;

    % set directions

    d1=z8-z1;
    d2=(a,0);
    d3=(a,b);
    d4=(0,b);
    d11=z18-z11; 
    d28=if ((a=1) and (b=-1)) or ((a=-1) and (b=1)) then right
	else: left
	fi;

    % set inner start point

    if unknown(y11) then
      z28=offset(z1,z8,start_weight,d28);
      y11=simy(z28,z18,x11)
    fi;

    % label points

    if grid and labels then
       labelpos(1,2,3,4,7,8,11,12,13,14,17,18)
    fi;

   (z1{d1}..z2{d2}..z3{d3}..z4{d4}..z7
    & z7..z17
    & reverse(z11{d11}..z12{d2}..z13{d3}..z14{d4}..z17)
    & z11..z1
    & cycle)				% final path

    if slant_switch then slanted slant fi

  endgroup

enddef;

% procedure for making arches in h,n,m

def n_arch(expr start_point,
		inner_edge,
		inner_width
		)=

  begingroup save d,x,y;numeric x[],y[];pair d[];

    z1=start_point;

    x2=0.57[x1,x4];
    x3=0.91[x1,x4];
    x4=x14+stroke_weight;
    x7=x4;
    x8=x2;

    x11=inner_edge;
    x12=0.67[x11,x14];
    x13=0.94[x11,x14];
    x14=x1+inner_width;
    x17=x14;
    x18=x12;

    y2=x_line+overshoot;
    y3=0.94[y7,y2];
    y4=0.75[y7,y2];
    y7=baseline;
    y8=1.14[y7,y2];

    y12=y2-horizontal_arch_weight;
    y13=0.95[y7,y12];
    y14=0.85[y7,y12];
    y17=y7;
    y18=1.10[y7,y12];

    arch(z)(upper_arch_spring_weight)

   endgroup

enddef;

% general procedures for drawing bowls

def bowl(suffix z)(expr start_weight,end_weight)=

% draws through points in z[], with standard numbering convention

% needs x11 and x17; calculates y11 and y17 if not given them

  begingroup save a,b,d,p;numeric a,b;pair d[];path p[];

    % set directions in path

    a=if x4>x1 then 1
      elseif x4<x1 then -1
      else: 0;errmessage("Left and right sides of bowl coincide")
      fi;

    b=if y2>y6 then -1
      elseif y2<y6 then 1
      else: 0;errmessage("Top and bottom of bowl coincide")
      fi;

    d1=z8-z1;
    d2=(a,0);
    d3=(a,b);
    d4=(0,b);
    d5=(-a,b);
    d6=(-a,0);
    d7=z7-z9;
    d28=(a,0);
    d29=(-a,0);

    % find inner start and finish points

    if unknown(y11) then
      z28=offset(z1,z8,start_weight,d28);
      y11=simy(z28,z18,x11)
    fi;

    if unknown(y17) then
    z29=offset(z7,z9,end_weight,d29);
    y17=simy(z29,z19,x11)
    fi;

    % set directions at inner start and finish points

    d11=z18-z11;
    d17=z17-z19;

    if grid and labels then 
      labelpos(1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19)
    fi;

    p1=z1{d1}..z2{d2}..z3{d3}..z4{d4}..
	z5{d5}..z6{d6}..z7{d7};		% outside of bowl

    p2=z11{d11}..z12{d2}..
	z13{d3}..
	tension 1.5 and 1..
	z14{d4}..
	tension 1 and 1.5..
	z15{d5}..
	z16{d6}..
	z17{d17};			% inside

    (p1 & z7..z17 & reverse(p2) & z11..z1 & cycle)

    if slant_switch then slanted slant fi	% final path

 endgroup

enddef; 


def cup(suffix z)=

% draws through points in z[], with standard numbering convention

% needs z11 and z17

  begingroup save a,b,d,p;numeric a,b;pair d[];path p[];

    % set directions in path

    a=if x7>x1 then 1
      elseif x7<x1 then -1
      else: 0;errmessage("Left and right sides of cup coincide")
      fi;

    b=if y4>y1 then 1
      elseif y4<y1 then -1
      else: 0;errmessage("Top and bottom of cup coincide")
      fi;

    d1=z8-z1;
    d2=(0,b);
    d3=(a,b);
    d4=(a,0);
    d5=(a,-b);
    d6=(0,-b);
    d7=z7-z9;
    d11=z18-z11;
    d17=z17-z19;

    if grid and labels then
       labelpos(1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19);
    fi;

    p1=if known(z2) then z1{d1}..z2{d2}
       else: z1{d1}
       fi..
       z3{d3}..z4{d4}..
       if known(z6) then z5{d5}..z6{d6}
       else: z5{d5}
       fi..
       z7{d7};				% outside of bowl

    p2=if known(z12) then z11{d11}..z12{d2}
       else: z11{d11}
       fi..
       z13{d3}..
	tension 1.5 and 1..
       z14{d4}..
	tension 1 and 1.5..
       if known(z16) then z15{d5}..z16{d6}
       else: z15{d5}
       fi..
       z17{d17};			% inside

    (p1 & z7..z17 & reverse(p2) & z11..z1 & cycle)

    if slant_switch then slanted slant fi	% final path

  endgroup

enddef;

% procedure for drawing terminals in a,c,s

def a_term(suffix z)=

% draws upper terminals in a,c,s; lower terminal in s

% outside is like arch; inside like cup

% outside skips z2 and z3 in standard numbering scheme

  begingroup save a,b,d,p;numeric a,b;pair d[];path p[];

  % set directions

    a=if x7>x1 then 1
      elseif x7<x1 then -1
      else: 0;errmessage("Left and right sides of curve coincide")
      fi;

    b=if y4>y1 then 1
      elseif y4<y1 then -1
      else: 0;errmessage("Top and bottom of curve coincide")
      fi;

    d1=z8-z1;
    d2=(0,b);
    d3=(a,b);
    d4=(a,0);
    d5=(a,-b);
    d6=(0,-b);
    d7=z7-z6;
    d11=z18-z11;
    d17=z17-z16;

  % add corner point at terminal

    x21=x1;
    y21=y11;

    if grid and labels then
       labelpos(1,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,21);
    fi;

    p1=z1{d1}..z4{d4}..z5{d5}..z6{d6}..z7{d7};	% outside of curve
 
    p2=if known(z12) then z11{d11}..z12{d2}
       else: z11{d11}
       fi..
       z13{d3}..
	tension 1.5 and 1..
       z14{d4}..
	tension 1 and 1.5..
       if known(z16) then z15{d5}..z16{d6}
       else: z15{d5}
       fi..
       z17{d17};				% inside

    (p1 & z7..z17 & reverse(p2) & z11..z21 & z21..z1 & cycle)

    if slant_switch then slanted slant fi	% final path

  endgroup

enddef;


% procedure for drawing bowls in b,d,p,q

def p_bowl(expr start_point,
		inner_edge,
		inner_width,
		bottom_edge,
		end_height,
		skew
		)=

  begingroup save x,y;numeric x[],y[];

    z1=start_point;

    x2=0.56[x1,x4];			% outer upper horizontal tangent x
    x4=x14+vertical_curve_weight;	%	right-hand edge
    x5=0.80[x11,x4]-skew;		%	lower 45-degree point
    x6=0.40[x11,x4]-skew;		%	      horizontal tangent
    x7=x1;				%	finish point

    x11=inner_edge;			% inner left-hand edge
    x12=0.51[x11,x14];			%	upper horizontal tangent x
    x14=x1+inner_width;			%	right-hand edge
    x15=x13-skew;			% 	lower 45-degree point
    x16=x12-skew;			%	      horizontal tangent
    x17=x11;				%	finish point

    y2=x_line+overshoot;		% outer upper horizontal tangent y
    y4=y14=0.5[y2,y6];			% vertical tangents
    y5=0.90[y2,y6];			% outer	lower 45-degree point
    y6=bottom_edge;			%	lower vertical reference
    y7=end_height;			%	finish point

    y12=y2-horizontal_arch_weight;	% inner upper horizontal tangent y
    y15=0.91[y12,y16];			%	lower 45-degree point
    y16=y6+horizontal_curve_weight;	%	      horizontal tangent

    z3=(0.82[x11,x4],0.94[y6,y2]);	% outer upper 45-degree point
    z13=(0.82[x11,x14],0.95[y16,y12]);	% inner

    z8=(x2,1.1[y6,y2]);			% outer	upper slope point
    z9=(x6,1.1[y2,y6]);			%	lower

    z18=(x12,1.06[y16,y12]);		% inner	upper start slope point
    z19=(x16,1.13[y12,y16]);		%	lower


    bowl(z)(upper_arch_spring_weight,lower_arch_spring_weight)

   endgroup

enddef;

% open a display window

numeric screen_width,screen_depth;
screen_width=480;screen_depth=400;

pair top_left,window_left,window_right;

top_left=(-10,ascender_line);		% this is in Metafont coordinates, with
					% the origin in the usual place

window_left=(0,0);
window_right=(screen_depth,screen_width); % these are in screen coordinates, with
					% the origin at the top left of the screen
					% and the first coordinate giving the depth

grid=if (mode=proof) or (mode=sun) then yes
else: no
fi;

if ddisplay then
  openwindow 1 from window_left to window_right at top_left
fi;